package com.duoduo.common.api.help;

import com.duoduo.common.api.constants.Constant;
import org.apache.commons.lang3.ArrayUtils;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.IntFunction;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.function.ToLongFunction;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

public class ArrayInnerUtil {
	
	public static boolean contains(String[] arr, String targetValue) {
	    return ArrayUtils.contains(arr,targetValue);
	}
	
	/**判断是否空list
	 * @param list
	 * @return
	 */
	public static <T> boolean isEmpty(T[] arr){
		return arr == null || arr.length == 0;
	}

	/**判断是否非空list
	 * @param list
	 * @return
	 */
	public static <T> boolean isNotEmpty(T[] arr){
		return arr != null && arr.length != 0;
	}

	/**Long[]转换long[]
	 * @param arr
	 * @return
	 */
	public static long[] longArrayToLongArray(Long[] arr){
		if(arr != null && arr.length > 0){
			return Arrays.stream(arr).mapToLong(id -> id).toArray();
		}
		return null;
	}

	/**int类型的数组转换为对象
	 * @param arr
	 * @param mapper
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T, R> R[] intArrayToRArray(int[] arr, IntFunction<? extends R> mapper, Class<?> clazz){
		List<R> list = Arrays.stream(arr).mapToObj(mapper).collect(toList());
		R[] t = (R[]) Array.newInstance(clazz, list.size());
		return list.toArray(t);
	}

	/**arr转换long[]
	 * @param arr
	 * @param mapper
	 * @return
	 */
	public static <T> long[] arrToLArr(T[] arr, ToLongFunction<? super T> mapper){
		return ListInnerUtil.streamToLArr(Arrays.stream(arr), mapper);
	}

	/**arr转换long[]
	 * @param arr
	 * @param mapper
	 * @return
	 */
	public static <T> long[] arrToLArr(T[] arr, Predicate<? super T> predicate, ToLongFunction<? super T> mapper){
		return ListInnerUtil.streamToLArr(Arrays.stream(arr), predicate, mapper);
	}

	/**int[]过滤
	 * @param arr
	 * @param mapper
	 * @return
	 */
	public static <T> int[] intArrToIArr(int[] arr, Predicate<? super Integer> predicate){
		return Arrays.stream(arr).boxed().filter(predicate).mapToInt(id -> id).toArray();
	}

	/**long[]过滤
	 * @param arr
	 * @param mapper
	 * @return
	 */
	public static <T> long[] longArrToLArr(long[] arr, Predicate<? super Long> predicate){
		return Arrays.stream(arr).boxed().filter(predicate).mapToLong(id -> id).toArray();
	}

	/**arr转换long[]
	 * @param arr
	 * @param mapper
	 * @return
	 */
	public static <T> long[] arrToLArr(Stream<T> stream, ToLongFunction<? super T> mapper){
		return ListInnerUtil.streamToLArr(stream, mapper);
	}

	/**long[]转换Long[]
	 * @param arr
	 * @return
	 */
	public static Long[] LongArrayTolongArray(long[] arr){
		if(arr != null && arr.length > 0){
			return Arrays.stream(arr).boxed().map(id -> id).toArray(Long[]::new);
		}
		return null;
	}
	
	public static Object[] listToArray(Collection<?> collection){
		return collection.stream().toArray();
	}

	/**String转换为Byte数组
	 * @param str
	 * @return
	 */
	public static Byte[] strToByteArray(String str){
		if(str.endsWith(",")){
			str = str.substring(0, str.length() - 1);
		}
		return Arrays.stream(str.split(",")).map(s -> Byte.parseByte(s)).toArray(Byte[]::new);
	}

	/**两个数组合并
	 * @param first
	 * @param second
	 * @return
	 */
	public static long [] concat(long[] first, long[] second) {
		long[] result = Arrays.copyOf(first, first.length + second.length);
		System.arraycopy(second, 0, result, first.length, second.length);
		return result;
	}

	/**求两个数组的差集
	 * @param arr1
	 * @param arr2
	 * @return
	 */
	public static long[] minus(long[] arr1, long[] arr2) {
		if(arr1 == null || arr1.length == 0){
			return arr1;
		}
		if(arr2 == null || arr2.length == 0){
			return arr1;
		}
	    List<Long> lst1 = Arrays.stream(arr1).boxed().collect(toList());
	    List<Long> lst2 = Arrays.stream(arr2).boxed().collect(toList());
	    lst1.removeAll(lst2);
	    return ListInnerUtil.longListToLongArray(lst1);
	}

	/**判断identityId是否在ids中存在
	 * @param ids
	 * @param identityId
	 * @return
	 */
	public static boolean contains(long[] ids, long identityId){
		if(ids == null || ids.length == 0){
			return false;
		}
		return Arrays.stream(ids).filter(id -> id == identityId).findFirst().isPresent();
	}
	
	/**过滤
	 * @param ids
	 * @param identityId
	 * @return
	 */
	public static int[] filter(int[] ids, IntPredicate predicate){
		if(ids == null || ids.length == 0){
			return ids;
		}
		return Arrays.stream(ids).filter(predicate).toArray();
	}
	
	/**对象数组过滤
	 * @param arrs
	 * @param type
	 * @param predicate
	 * @return 全部不匹配则返回null
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] filter(T[] arrs, Class<T> type, Predicate<T> predicate){
		if(arrs == null || arrs.length == 0){
			return arrs;
		}
		Object[] objResultArr = Arrays.stream(arrs).filter(predicate).toArray(Object[]::new);
		if(isNotEmpty(objResultArr)) {
			T[] result = genericArray(type, objResultArr.length);
			for (int i=0; i<result.length; i++) {
				result[i] = (T)objResultArr[i];
			}
			return result;
		}
		return null;
	}

	/**
	 * 去重
	 */
	public static long[] distinct(long[] arr) {
	    return Arrays.stream(arr).distinct().toArray();
	}

	/**判断数组里的所有元素是否都相等
	 * @param arr
	 * @return 数组为空或大小为0，或不是全相等，返回false
	 */
	public static <T> boolean equalArr(T[] arr){
		if(arr == null || arr.length == 0){
			return false;
		}
		if(arr.length == 2){
			return arr[0] == arr[1];
		}
		for(int i=0; i<arr.length-2; i++){
		    if(arr[i] != arr[i+1]){
		        return false;
		    }
		}
		return true;
	}

	/**判断对象是否是数组
	 * @param obj
	 * @return
	 */
	public static boolean isArray(Object obj){
		return obj.getClass().isArray();
	}

	/**对象转数组
	 * @param obj
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] obj2Array(Object obj, Class<T> type){
		int length = Array.getLength(obj);
		T[] arr = genericArray(type, length);
	    for (int i = 0; i < arr.length; i++) {
	    	arr[i] = (T)Array.get(obj, i);
	    }
	    return arr;
	}

	/**生成泛型数组
	 * @param type
	 * @param length
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] genericArray(Class<T> type, int length){
		return (T[]) Array.newInstance(type, length);
	}
	
	public static <T> String toString(final T[] array) {
        return toString(array, "{}");
    }
	
	private static <T> String toString(final T[] array, final String stringIfNull) {
        if (isEmpty(array)) {
            return stringIfNull;
        }
        StringBuffer sb = new StringBuffer("{}");
        for (int i=0; i<array.length; i++) {
        	T t = array[i];
        	if(i < array.length - 1){
        		if(t == null){
        			sb.append(Constant.BLANK).append(Constant.COMMA);
        		}else{
        			sb.append(t.toString()).append(Constant.COMMA);
        		}
        	}else{
        		if(t == null){
        			sb.append(Constant.BLANK);
        		}else{
        			sb.append(t.toString());
        		}
        	}
		}
        return sb.toString();
    }

}
